function varargout = gui_export(varargin)
% GUI_EXPORT MATLAB code for gui_export.fig
%      GUI_EXPORT, by itself, creates a new GUI_EXPORT or raises the existing
%      singleton*.
%
%      H = GUI_EXPORT returns the handle to a new GUI_EXPORT or the handle to
%      the existing singleton*.
%
%      GUI_EXPORT('CALLBACK',hObject,eventData,handles,...) calls the local
%      function named CALLBACK in GUI_EXPORT.M with the given input arguments.
%
%      GUI_EXPORT('Property','Value',...) creates a new GUI_EXPORT or raises the
%      existing singleton*.  Starting from the left, property value pairs are
%      applied to the GUI before gui_export_OpeningFcn gets called.  An
%      unrecognized property name or invalid value makes property application
%      stop.  All inputs are passed to gui_export_OpeningFcn via varargin.
%
%      *See GUI Options on GUIDE's Tools menu.  Choose "GUI allows only one
%      instance to run (singleton)".
%
% See also: GUIDE, GUIDATA, GUIHANDLES

% Edit the above text to modify the response to help gui_export

% Last Modified by GUIDE v2.5 10-Oct-2012 09:44:34

% Begin initialization code - DO NOT EDIT
gui_Singleton = 1;
gui_State = struct('gui_Name',       mfilename, ...
                   'gui_Singleton',  gui_Singleton, ...
                   'gui_OpeningFcn', @gui_export_OpeningFcn, ...
                   'gui_OutputFcn',  @gui_export_OutputFcn, ...
                   'gui_LayoutFcn',  [] , ...
                   'gui_Callback',   []);
if nargin && ischar(varargin{1})
    gui_State.gui_Callback = str2func(varargin{1});
end

if nargout
    [varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
else
    gui_mainfcn(gui_State, varargin{:});
end
% End initialization code - DO NOT EDIT


% isFrames - check whether the project source is frames
function isf = isFrames(projectStruct)
isf = strcmpi(projectStruct.inFile.kind,'imageMatlabOrDpx');


% --- Executes just before gui_export is made visible.
function gui_export_OpeningFcn(hObject, eventdata, handles, varargin)
% This function has no output args, see OutputFcn.
% hObject    handle to figure
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
% varargin   command line arguments to gui_export (see VARARGIN)

% Choose default command line output for gui_export
handles.output = hObject;

% Update handles structure
guidata(hObject, handles);

try
    
    % fix layout
    extent = get(handles.preserve_aspect_checkbox, 'Extent');
    pos = get(handles.preserve_aspect_checkbox, 'Position');
    fontsize = get(handles.preserve_aspect_checkbox, 'FontSize');
    while(extent(3) > pos(3)-2*pos(4))
        fontsize = fontsize * 0.9;
        set(handles.preserve_aspect_checkbox, 'FontSize', fontsize);
        extent = get(handles.preserve_aspect_checkbox, 'Extent');
    end

    gui_main = find(strcmp(varargin, 'gui_main'));
    if (isempty(gui_main)) || (length(varargin) <= gui_main) || ...
            (~ishandle(varargin{gui_main+1}))
        dontOpen = true;
    else
        handles.gui_main = varargin{gui_main+1};
        handlesMain = guidata(handles.gui_main);
        handles.project = handlesMain.project;
        handles.projectStruct = handlesMain.projectStruct;
        handles.pref = handlesMain.pref;
        guidata(hObject, handles);

        num_film = size(handlesMain.pref.film_type,2);
        menustr{num_film} = ''; % preallocate
        for i = 1:num_film
            menustr{i} = sprintf('%s (%+d)', ...
                handlesMain.pref.film_type(i).name, ...
                handlesMain.pref.film_type(i).offset);
        end
        menustr{num_film+1} = 'New (Specify) ...';

        set(handles.frame_offset_popup, 'String', menustr);

        if(isfield(handles.project,'film_type'))
            found_film = 0;
            for i =1:num_film
                if((strcmp(handles.project.film_type.name, ...
                        handlesMain.pref.film_type(i).name)) && ...
                        (handles.project.film_type.offset == ...
                        handlesMain.pref.film_type(i).offset))
                    found_film = 1;
                    break;
                end
            end
            if(~found_film)
                num_film = num_film + 1;
                menustr{num_film+1} = menustr{num_film};
                menustr{num_film} = sprintf('%s (%+d)', ...
                    handles.project.film_type.name, ...
                    handles.project.film_type.offset);
                set(handles.frame_offset_popup, 'String', menustr);
            end
            set(handles.frame_offset_popup, 'Value', i);
        else
            set(handles.frame_offset_popup, 'Value', ...
                handlesMain.pref.film_type_default);
            handles.project.film_type = handlesMain.pref.film_type(...
                handlesMain.pref.film_type_default);
        end     

        exportOption{1} = 'Audio only';
        exportOption{2} = 'Video with audio';
        if(isFrames(handles.projectStruct))
            exportOption{3} = 'Video only';
        end
        set(handles.export_popup, 'String', exportOption);

        set(handles.video_width_text, 'String', ...
            num2str(handles.projectStruct.width));
        set(handles.video_height_text, 'String', ...
            num2str(handles.projectStruct.height));

        handles.aspectRatio = double(handles.projectStruct.width) / ...
            handles.projectStruct.height;

        guidata(hObject, handles);

        gui_set(handles.export_popup, 'Value', 1);

        % UIWAIT makes gui_export wait for user response (see UIRESUME)
        uiwait(hObject);
    end
catch exception
    gui_exception(exception);
	dontOpen = true;
end



% --- Outputs from this function are returned to the command line.
function varargout = gui_export_OutputFcn(hObject, eventdata, handles) 
% varargout  cell array for returning output args (see VARARGOUT);
% hObject    handle to figure
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Get default command line output from handles structure
varargout{1} = handles.output;
delete(hObject);



% --- Executes when user attempts to close export_figure.
function export_figure_CloseRequestFcn(hObject, eventdata, handles)
% hObject    handle to export_figure (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hint: delete(hObject) closes the figure
gui_close_figure(handles.export_figure);



function enable_video(handles, tog)
try
    set(handles.original_video_button, 'Enable', tog);
    set(handles.reencode_video_button, 'Enable', tog);
    if(get(handles.reencode_video_button, 'Value'))
        enable_video_encode(handles, tog)
    else
        enable_video_encode(handles, 'off')
    end    
catch exception
    gui_exception(exception);
end

function enable_video_encode(handles, tog)
try
    set(handles.reencode_video_button, 'Enable', tog);
    set(handles.video_width_label, 'Enable', tog);
    set(handles.video_width_text, 'Enable', tog);
    set(handles.video_height_label, 'Enable', tog);
    set(handles.video_height_text, 'Enable', tog);
    set(handles.preserve_aspect_checkbox, 'Enable', tog);
    set(handles.video_compression_popup, 'Enable', tog);
    set(handles.video_bitrate_label, 'Enable', tog);
    set(handles.video_bitrate_text, 'Enable', tog);
    set(handles.video_bitrate_units_label, 'Enable', tog);

    if(strcmp(tog,'on'))
        gui_set(handles.video_compression_popup, 'Value', ...
            get(handles.video_compression_popup, 'Value'));
    end
catch exception
    gui_exception(exception);
end

function enable_audio(handles, tog)
try
    set(handles.audio_bitdepth_label, 'Enable', tog);
    set(handles.audio_bitdepth_popup, 'Enable', tog);
    set(handles.audio_sampling_rate_label, 'Enable', tog);
    set(handles.audio_sampling_rate_popup, 'Enable', tog);
catch exception
    gui_exception(exception);
end

function enable_av(handles, tog)
try
    set(handles.frame_offset_label, 'Enable', tog);
    set(handles.frame_offset_popup, 'Enable', tog);
catch exception
    gui_exception(exception);
end

% --- Executes on selection change in export_popup.
function export_popup_Callback(hObject, eventdata, handles)
% hObject    handle to export_popup (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: contents = cellstr(get(hObject,'String')) returns export_popup contents as cell array
%        contents{get(hObject,'Value')} returns selected item from export_popup

try
    if(isFrames(handles.projectStruct))
        set(handles.reencode_video_button, 'Value', 1.0);
    end

    idx = get(hObject,'Value');
    strArr = cellstr(get(hObject, 'String'));
    switch(lower(strArr{idx}))
        case 'video with audio'
            enable_video(handles, 'on');
            enable_audio(handles, 'on');
            enable_av(handles, 'on');
        case 'video only'
            enable_video(handles, 'on');
            enable_audio(handles, 'off');
            enable_av(handles, 'off');
        case 'audio only'
            enable_video(handles, 'off');
            enable_audio(handles, 'on');
            enable_av(handles, 'off');
        case 'frames + audio'
            enable_video(handles, 'off');
            enable_audio(handles, 'on');
            enable_av(handles, 'off');
    end

    if(isFrames(handles.projectStruct))
        set(handles.reencode_video_button, 'Value', 1.0);
        set(handles.original_video_button, 'Enable', 'off');
    else
        set(handles.original_video_button, 'Value', 1.0);
        enable_video_encode(handles, 'off');
        set(handles.reencode_video_button, 'Enable', 'off');    
    end
catch exception
    gui_exception(exception);
end


% --- Executes during object creation, after setting all properties.
function export_popup_CreateFcn(hObject, eventdata, handles)
% hObject    handle to export_popup (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: popupmenu controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end


% --- Executes on button press in play_checkbox.
function play_checkbox_Callback(hObject, eventdata, handles)
% hObject    handle to play_checkbox (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hint: get(hObject,'Value') returns toggle state of play_checkbox



function video_width_text_Callback(hObject, eventdata, handles)
% hObject    handle to video_width_text (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'String') returns contents of video_width_text as text
%        str2double(get(hObject,'String')) returns contents of video_width_text as a double
try
    val = str2num(get(hObject, 'String'));
    if(isempty(val) || val <= 0)
        val = handles.projectStruct.width;
        set(hObject, 'String', num2str(val));
    elseif(val ~= round(val))
        val = round(val);
        set(hObject, 'String', num2str(val));
    end
    if(get(handles.preserve_aspect_checkbox,'Value'))
        h = round(double(val) / handles.aspectRatio);
        set(handles.video_height_text, 'String', num2str(h));
    end
catch exception
    gui_exception(exception);
end

% --- Executes during object creation, after setting all properties.
function video_width_text_CreateFcn(hObject, eventdata, handles)
% hObject    handle to video_width_text (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: edit controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end



function video_height_text_Callback(hObject, eventdata, handles)
% hObject    handle to video_height_text (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'String') returns contents of video_height_text as text
%        str2double(get(hObject,'String')) returns contents of video_height_text as a double
try
    val = str2num(get(hObject, 'String'));
    if(isempty(val) || val <= 0)
        val = handles.projectStruct.height;
        set(hObject, 'String', num2str(val));
    elseif(val ~= round(val))
        val = round(val);
        set(hObject, 'String', num2str(val));
    end
    if(get(handles.preserve_aspect_checkbox,'Value'))
        w = round(double(val) * handles.aspectRatio);
        set(handles.video_width_text, 'String', num2str(w));
    end
catch exception
    gui_exception(exception);
end


% --- Executes during object creation, after setting all properties.
function video_height_text_CreateFcn(hObject, eventdata, handles)
% hObject    handle to video_height_text (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: edit controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end


% --- Executes on button press in preserve_aspect_checkbox.
function preserve_aspect_checkbox_Callback(hObject, eventdata, handles)
% hObject    handle to preserve_aspect_checkbox (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hint: get(hObject,'Value') returns toggle state of preserve_aspect_checkbox



function video_bitrate_text_Callback(hObject, eventdata, handles)
% hObject    handle to video_bitrate_text (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'String') returns contents of video_bitrate_text as text
%        str2double(get(hObject,'String')) returns contents of video_bitrate_text as a double


% --- Executes during object creation, after setting all properties.
function video_bitrate_text_CreateFcn(hObject, eventdata, handles)
% hObject    handle to video_bitrate_text (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: edit controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end


% --- Executes on button press in h264_checkbox.
function h264_checkbox_Callback(hObject, eventdata, handles)
% hObject    handle to h264_checkbox (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hint: get(hObject,'Value') returns toggle state of h264_checkbox


% --- Executes on selection change in audio_bitdepth_popup.
function audio_bitdepth_popup_Callback(hObject, eventdata, handles)
% hObject    handle to audio_bitdepth_popup (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: contents = cellstr(get(hObject,'String')) returns audio_bitdepth_popup contents as cell array
%        contents{get(hObject,'Value')} returns selected item from audio_bitdepth_popup


% --- Executes during object creation, after setting all properties.
function audio_bitdepth_popup_CreateFcn(hObject, eventdata, handles)
% hObject    handle to audio_bitdepth_popup (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: popupmenu controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end


% --- Executes on selection change in audio_sampling_rate_popup.
function audio_sampling_rate_popup_Callback(hObject, eventdata, handles)
% hObject    handle to audio_sampling_rate_popup (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: contents = cellstr(get(hObject,'String')) returns audio_sampling_rate_popup contents as cell array
%        contents{get(hObject,'Value')} returns selected item from audio_sampling_rate_popup


% --- Executes during object creation, after setting all properties.
function audio_sampling_rate_popup_CreateFcn(hObject, eventdata, handles)
% hObject    handle to audio_sampling_rate_popup (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: popupmenu controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end


% --- Executes on selection change in frame_offset_popup.
function frame_offset_popup_Callback(hObject, eventdata, handles)
% hObject    handle to frame_offset_popup (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: contents = cellstr(get(hObject,'String')) returns frame_offset_popup contents as cell array
%        contents{get(hObject,'Value')} returns selected item from frame_offset_popup
try
    string_list = cellstr(get(hObject, 'String'));
    idx = get(hObject, 'Value');
    if(idx == size(string_list,1))
        answer = inputdlg({'Film type:', 'Sound separtion value:'},...
            'Custom Film Type', [1 30;1 30], {'Custom', '+0'});
        if ~isempty(answer)
            string_list{idx+1} = string_list{idx};
            offset = str2num(answer{2});
            string_list{idx} = sprintf('%s (%+d)', answer{1}, offset);
            set(hObject,'String',string_list);

            handles.project.film_type.name = answer{1};
            handles.project.film_type.offset = offset;

            handles.pref.film_type(idx) = handles.project.film_type;
        else
            set(hObject,'Value',idx-1);
        end
    else
        handles.project.film_type = handles.pref.film_type(idx);
    end
    guidata(hObject, handles);
catch exception
    gui_exception(exception);
end



% --- Executes during object creation, after setting all properties.
function frame_offset_popup_CreateFcn(hObject, eventdata, handles)
% hObject    handle to frame_offset_popup (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: popupmenu controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end


% --- Executes on button press in cancel_button.
function cancel_button_Callback(hObject, eventdata, handles)
% hObject    handle to cancel_button (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
gui_close_figure(handles.export_figure);



% Extract output format parameters from GUI export window
% handles    structure with handles and user data (see GUIDATA)
function fmt = get_format(handles)

try
    outTypeIdx = get(handles.export_popup, 'Value');
    outTypeArr = get(handles.export_popup, 'String');
    fmt.outType = outTypeArr{outTypeIdx};

    fmt.do_audio = false;
    fmt.do_video = false;
    fmt.do_frames = false;

    if(strncmpi(fmt.outType,'Audio', 5))
        fmt.do_audio = true;
    elseif(strncmpi(fmt.outType,'Frames', 5))
        fmt.do_audio = true;
        fmt.do_frames = true;
    else
        fmt.do_video = true;
        if(strncmpi(fmt.outType,'Video with', 10))
            fmt.do_audio = true;
        end
    end

    if(fmt.do_video)
        fmt.video.copy = get(handles.original_video_button, 'Value');
        fmt.video.codec = 'copy';
        if(~fmt.video.copy)
            w = str2num(get(handles.video_width_text, 'String'));
            if(isempty(w) || w<0)
                w = 0;
            end
            h = str2num(get(handles.video_height_text, 'String'));
            if(isempty(h) || h<0)
                h = 0;
            end

            fmt.video.width = w; 
            fmt.video.height = h;

            fmt.video.pixfmt = '';
            %fmt.video.pixfmt = 'yuv420p';
            fmt.video.bitrate = '';

            strarr = cellstr(get(handles.video_compression_popup,'String'));
            sel = strarr{get(handles.video_compression_popup,'Value')};

            switch(sel)
                case 'ProRes'
                    fmt.video.codec = 'prores';
                case 'H.264'
                    fmt.video.codec = 'libx264';
                    bitrate = str2num(get(handles.video_bitrate_text,'String'));
                    fmt.video.bitrate = uint16(bitrate);
                case 'Uncompressed'
                    fmt.video.codec = 'rawvideo';
                    %fmt.pixfmt = 'rgb48le';
            end
        end
    end

    if(fmt.do_audio)
        if(fmt.do_video)
            % offset is already stored in project
        end

        idx = get(handles.audio_bitdepth_popup, 'Value');
        bitdeptharr = get(handles.audio_bitdepth_popup, 'String');
        fmt.audio.bitdepth = str2num(bitdeptharr{idx});

        idx = get(handles.audio_sampling_rate_popup, 'Value');
        ratearr = get(handles.audio_sampling_rate_popup, 'String');
        rate = sscanf(ratearr{idx}, '%f');
        if(~isempty(rate))
            fmt.audio.sampling_rate = rate * 1000;
        else
            fmt.audio.sampling_rate = [];
        end

    end
catch exception
    gui_exception(exception);
end



% Run ffmpeg command in background and show progress in waitbar
% cmd      ffmpeg cmd string, complete except for redirection
% logfile  name of file into which output from cmd will be directed
% n        number of frames expected (for normalizing waitbar)
% msg      message to display in the waitbar
function ffbar(cmd, logfile, n, msg)

bar = waitbar(0, msg);

try
    if(isunix)
        redir = ['> "' logfile '" 2> "' logfile '"'];
    else
        redir = ['> "' logfile '"'];
    end

    cmdline = [cmd ' ' redir ' &'];
    %msgbox(cmdline);
    %close(bar);
    %return

    %fp = fopen('ffcmds.txt','a');
    %fprintf(fp,'%s %s\n',datestr(now), cmd);
    %fclose(fp);

    [status output ] = system(cmdline);
    if(status > 0)
        while true
            action = questdlg('Badly formed command.', ...
                'Command Error', 'Dismiss','Show Command','Show Command');
            switch action
                case 'Show Command'
                    answer = inputdlg(...
                        {'ffmpeg command','system output'},...
                        'ffmpeg command', 6,...
                        {cmdline, output}, 'on');
                case 'Dismiss'
                    return
            end
        end
        return
    end

    prevSize = -1;
    stall = 0;
    readpos = 0;
    while true
        uiwait(bar,1);
        flog = fopen(logfile);
        fseek(flog, 0, 'eof');
        s = ftell(flog)
        if(s == prevSize)
            fclose(flog);
            stall = stall + 1;
            if(stall > 10)
                done = false;
                while ~done
                    action = questdlg(...
                        'ffmpeg may not have run successfully.', ...
                        'FFmpeg Error', ...
                        'Dismiss','Show Command', 'Open Log File','Dismiss');
                    switch action
                        case 'Show Command'
                            inputdlg('ffmpeg command',...
                                'ffmpeg command', 6, {cmdline}, 'on');
                        case 'Open Log File'
                            if(ispc)
                                system(['start ' logfile]);
                            else
                                system(['open ' logfile]);
                            end
                        case 'Dismiss'
                            done = true;
                    end
                end
                break;
            else
                continue;
            end
        else
            stall = 0;
            prevSize = s;
        end

        if(s - readpos < 100)
            readpos = s - 100;
            if(readpos < 0)
                readpos = 0;
            end
        end
        
        fseek(flog, readpos, 'bof');
        l = fread(flog, s - readpos, 'uint8=>char')';
        if(~isempty(strfind(l, 'global header')))
            break;
        end
        pos = strfind(l,'frame=');
        if(~isempty(pos))
            pos = pos(end);
            f = sscanf(l(pos:end),'frame= %d');
            frac = double(f)/double(n);
            waitbar(frac, bar, ['Exporting frame ' num2str(f) '/' ...
                num2str(n)]);
        end
        fclose(flog);
    end
catch exception
    gui_exception(exception);
end

close(bar)




% --- Executes on button press in export_button.
function export_button_Callback(hObject, eventdata, handles)
% hObject    handle to export_button (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

try
    
project = handles.project;
projectStruct = handles.projectStruct;

cmd = 'ffmpeg -y';

fmt = get_format(handles);

nFrames = project.frame_out - project.frame_in + 1;
nStreams = 0;

if(fmt.do_audio)

    need_render = false;
    inaudio_single = ['-i "' project.audio_file_arr{1} '"'];
    inaudio = inaudio_single;
    if(~exist(project.audio_file_arr{1},'file'))
        need_render = true;
    end
    n = size(project.audio_file_arr,2);
    for i=2:n
        inaudio = [inaudio ' -i "' project.audio_file_arr{i} '"'];
        if(~exist(project.audio_file_arr{i},'file'))
            need_render = true;
        end
    end

    if(need_render)
        action = questdlg({'Sound render files not found.',...
            'Render now? (This may take a long time)'},...
            'Missing Render','Cancel','Render Sound','Render Sound');
        switch(action)
            case 'Cancel'
                return;
            case 'Render Sound'
                gui_extract_sound(guidata(handles.gui_main));
                handlesMain = guidata(handles.gui_main);
                handles.project = handlesMain.project;
                handles.projectStruct = handlesMain.projectStruct;
        end
    end
    
    % data format in the existing .wav file
    if(isfield(projectStruct,'samplingRate') && ...
            isfield(projectStruct.samplingRate, 'native'))
        wav_sampling_rate = projectStruct.samplingRate.native;
    else
        wav_sampling_rate = 48000;
    end
    
    wav_bitdepth = projectStruct.bitDepth.choicesCellArr{...
        projectStruct.bitDepth.currChoiceInd};

    if(isempty(fmt.audio.sampling_rate) || fmt.audio.sampling_rate <= 0)
        fmt.audio.sampling_rate = wav_sampling_rate;
    end

    if(isempty(fmt.audio.bitdepth) || fmt.audio.bitdepth <= 0)
        fmt.audio.bitdepth = wav_bitdepth;
    end
    
    if(fmt.audio.bitdepth > 8)
        sbit = 's';
        endian = 'le';
    else
        sbit = 'u';
        endian = '';
    end
    
    if(fmt.audio.sampling_rate == wav_sampling_rate &&...
            fmt.audio.bitdepth == wav_bitdepth) 
        aflags = '-c:a copy';
    else
        aflags = sprintf('-c:a pcm_%s%d%s -ar %d',...
            sbit, fmt.audio.bitdepth, endian, ...
            fmt.audio.sampling_rate);
    end
            
    nStreams = nStreams + n;
end

if(fmt.do_video)
    
    vflags = ['-c:v ' fmt.video.codec];
    switch(fmt.video.codec)
        case 'libx264'
            if(~isempty(fmt.video.bitrate) && fmt.video.bitrate>0)
                vflags = sprintf(...
                    '%s -pix_fmt yuv420p -x264opts bitrate=%d', ...
                    vflags, fmt.video.bitrate);
            end
        case 'mpeg4'
            if(~isempty(fmt.video.bitrate) && fmt.video.bitrate>0)
                vflags = sprintf('%s -b:v %dK', vflags, fmt.video.bitrate);
            end
        %case 'prores'
        %case 'rawvideo'
        %case 'copy'
    end

    % if muxing, use the specified offet
    if(fmt.do_audio)
        offset = project.film_type.offset;
    else
        offset = 0;
    end
    
    if(isFrames(projectStruct))
        fps = 24;
        
        % skip to the sync frame
        frame = project.frame_in + offset;
        delay = 0;
        
        % if we've skipped past the first frame, use a delay instead
        if(frame < projectStruct.inFile.frameRangeArr(1))
            delay = offset/fps;
            frame = project.frame_in;
        end

        invideo = ['-framerate ' num2str(fps) ...
            ' -start_number ' num2str(frame) ...
            ' -i "' projectStruct.inFile.dirPath ...
            projectStruct.inFile.namePrefixNoPath '%0' ...
            num2str(projectStruct.inFile.indFieldLength) 'd.' ...
            projectStruct.inFile.fileExt '"' ...
            ' '];
    else
        fps = projectStruct.frameRate;
        invideo = ['-i "' project.source '"'];
        delay = offset/fps;
    end

    if(~fmt.video.copy)
        if(fmt.video.width ~= projectStruct.width || ...
                fmt.video.height ~= projectStruct.height)
            vflags = sprintf('%s -s %dx%d', vflags, ...
                fmt.video.width, fmt.video.height);
        end
    end
    
    nStreams = nStreams + 1;
end    

% Unmuxed audio (alone or with frames)
if(fmt.do_audio && ~fmt.do_video)
    
    % with frames? Ask for an output directory to create
    if(fmt.do_frames)
        [filename pathname] = uiputfile({'*', 'new directory'},...
            'Write Frames + Audio Into Directory');
        idx = 0;
        if isequal(filename, 0)
            return
        end
        
        % if it exists as a file, replace it. If it doesn't exist,
        % create it.
        if(exist([pathname filename],'file'))
            if(~exist([pathname filename],'dir'))
                delete([pathname filename]);
                mkdir(pathname, filename);
            end
        else
            mkdir(pathname, filename);
        end
        
        % reset path to include the new directory
        pathname = [pathname filename filesep];
        outfile = [pathname 'audio.avi'];
        
    % without frames? ask for an audio container
    else
        [filename pathname idx] = uiputfile({...
            '*.wav', 'single track .wav file(s)';...
            '*.avi', 'multi-track .avi';...
            },...
            'Export Audio As');
        if isequal(filename, 0)
            return
        end
        outfile = [pathname filename];
    end
    
    doEncode = true;
    
    % Can we copy the file(s) to the output?
    
    if(idx == 1 &&...
            fmt.audio.sampling_rate == wav_sampling_rate &&...
            fmt.audio.bitdepth == wav_bitdepth) 
        doEncode = false;
        copyto = outfile;
        
        for track = 1:nStreams
        
            copyfrom = project.audio_file_arr{track};
            if(track > 1)
                [newfn newpath] = uiputfile('*.wav',...
                    ['Track ', num2str(track)],...
                    copyto);
                if(isequal(newfn, 0))
                    return;
                end
                copyto = [newpath newfn];
            end

            [status msg] = copyfile(copyfrom, copyto, 'f');

            if(status==0)
                if(ispc)
                    cpy = 'copy "%s" "%s" /y';
                else
                    cpy = 'cp -f "%s" "%s"';
                end
                debug_copy = sprintf(cpy, ...
                    copyfrom, copyto)
                [status output] = system(sprintf(cpy, ...
                    copyfrom, copyto))

                if(status>0)
                    nextstep = questdlg({'Copy sound file failed with error:',...
                        msg, output}, ...
                        'Error', 'Cancel', 'Try FFmpeg', 'Try FFmpeg');
                    switch nextstep,
                        case 'Cancel',
                            doEncode = false;
                            return;
                        case 'Try FFmpeg',
                            doEncode = true;
                    end
                end
            end
            if doEncode
                break;
            end
        end
    end
    
    if(doEncode) 
        if(idx == 1)
            trackfile = outfile;
            for track = 1:nStreams
                infile = ['-i "' project.audio_file_arr{track} '"'];
                if(track > 1)
                    [newfn newpath] = uiputfile('*.wav',...
                        ['Track ', num2str(track)],...
                        trackfile);
                    if(isequal(newfn, 0))
                        return;
                    end
                    trackfile = [newpath newfn];
                end
                cmdline = [cmd ' ' infile ' ' aflags ' "' trackfile '"'];
                ffbar(cmdline, [project.scratch_directory 'ffmpegout.log'], ...
                    nFrames, ['Exporting audio track ', num2str(track)]);
            end
        else
            infile = inaudio;
            mapflags = '';
            if(nStreams > 1)
                for i = 1:nStreams
                    mapflags = [mapflags ' -map ' num2str(i-1) ];
                end
            end
        
            cmdline = [cmd ' ' infile ' ' aflags ' ' mapflags ' "' outfile '"'];
            ffbar(cmdline, [project.scratch_directory 'ffmpegout.log'], ...
                nFrames, 'Exporting audio');
        end
        
        %[status output] = system(cmdline)
        %f(status > 0)
        %    errordlg('ffmpeg failed. See console output.', ...
        %        'FFmpeg Error', 'modal');
        %    ffmpeg = output
        %    return
        %end
        
        if(fmt.do_frames)
            if(isFrames(projectStruct))
                wb = waitbar(0,'Exporting frames');
                for i=1:nFrames
                    copyfile(...
                        sprintf('%s%s%0*d.%s',...
                        projectStruct.inFile.dirPath, ...
                        projectStruct.inFile.namePrefixNoPath, ...
                        projectStruct.inFile.indFieldLength, ...
                        project.frame_in + i, ...
                        projectStruct.inFile.fileExt), ...
                        sprintf('%s%s%0*d.%s',...
                        pathname, ...
                        projectStruct.inFile.namePrefixNoPath, ...
                        projectStruct.inFile.indFieldLength, ...
                        project.frame_in + i, ...
                        projectStruct.inFile.fileExt));
                    waitbar(double(i)/double(nFrames), wb);
                end
                close(wb);
            else
                cmdline = [cmd ' -i "' project.source '" "' pathname ...
                    '%0' num2str(ceil(log10(nFrames+1))) 'd.dpx'];
                ffbar(cmdline, ...
                    [project.scratch_directory 'ffmpegout.log'], ...
                    nframes, 'Exporting frames');
            end
        end
    end
else
    filetype = {...
        '*.avi', 'AVI video'; ...
        '*.mov', 'Quicktime video';...
        '*.mp4', 'Mpeg4 video'};
    
    [filename pathname kind] = uiputfile(filetype, 'Export Video As');
    if isequal(filename, 0)
        return
    end

    ext = filetype{kind,1}(3:end);

    outfile = [pathname filename];

    if(fmt.do_audio)
        if(delay == 0)
            infile = [ invideo ' ' inaudio_single ];
        elseif(delay > 0)
            if(isFrames(projectStruct))
                tmpvideo = [ '"' project.scratch_directory 'tmpvideo.' ext '"'];
                tmpflags = vflags;
                posttmp = '-c:v copy';
            else
                tmpvideo = [ '"' project.scratch_directory 'tmpvideo.' ...
                    projectStruct.inFile.fileExt '"'];
                tmpflags = '-c:v copy';
                posttmp = vflags;
            end
            wb = waitbar(0.1,'Trimming video for sync');
            trimcmd = [cmd ' -ss ' num2str(delay) ' ' invideo ' ' tmpflags ...
                ' -frames ' num2str(nFrames) ' ' tmpvideo];
            [status output] = system(trimcmd);
            close(wb);
            if(status > 0)
                done = false;
                while ~done
                    action = questdlg(...
                        'ffmpeg did not run successfully.', ...
                        'FFmpeg Error', ...
                        'Dismiss','Show Details','Dismiss');
                    switch action
                        case 'Show Details'
                            inputdlg({'ffmpeg command','system output'},...
                                'ffmpeg command', 6, {trimcmd,output}, 'on');
                        case 'Dismiss'
                            done = true;
                    end
                end
                return
            end

            infile = [ '-i ' tmpvideo ' ' inaudio_single ];
            vflags = posttmp;
        else
            tmpaudio = [ '"' project.scratch_directory 'tmpaudio.wav"' ];
            wb = waitbar(0.1, 'Trimming audio for sync');
            trimcmd = [cmd ' -ss ' num2str(-delay) ' ' inaudio_single ...
                ' -c:a copy ' tmpaudio];
            [status output] = system(trimcmd);
            close(wb);
            if(status > 0)
                done = false;
                while ~done
                    action = questdlg(...
                        'ffmpeg did not run successfully.', ...
                        'FFmpeg Error', ...
                        'Dismiss','Show Details', 'Dismiss');
                    switch action
                        case 'Show Details'
                            inputdlg({'ffmpeg command','system output'},...
                                'ffmpeg command', 6, {trimcmd,output}, 'on');
                        case 'Dismiss'
                            done = true;
                    end
                end
                return
            end
            infile = [ invideo ' -i ' tmpaudio ' ' aflags ];
        end
    else
        infile = invideo;
    end
    
    cmdline =  [ cmd ' ' infile ' ' vflags ' ' aflags ...
        ' -frames ' num2str(nFrames) ' -map 0:0 -map 1:0 ' ...
        '"' outfile '"'];
    ffbar(cmdline, [project.scratch_directory 'ffmpegout.log'], ...
        nFrames, 'Exporting');
end

%if(exist(outfile, 'file'))
    player = get(handles.play_checkbox, 'Value');
    if(player)
        if(ispc)
            [status output] = system(['start "' outfile '"']);
        else
            [status output] = system(['open "' outfile '"']);
        end
        
        if(status > 0)
            errordlg({'Call to media player failed:',output'},'Error',...
                'modal');
        else
            gui_close_figure(handles.export_figure);
        end
    end
%else
%    errordlg([outfile ' not written. Check ffmpegout.log']);
%end

catch exception
    gui_exception(exception);
end


% --- Executes when selected object is changed in video_panel.
function video_panel_SelectionChangeFcn(hObject, eventdata, handles)
% hObject    handle to the selected object in video_panel 
% eventdata  structure with the following fields (see UIBUTTONGROUP)
%	EventName: string 'SelectionChanged' (read only)
%	OldValue: handle of the previously selected object or empty if none was selected
%	NewValue: handle of the currently selected object
% handles    structure with handles and user data (see GUIDATA)
if(get(handles.original_video_button,'Value'))
    enable_video_encode(handles, 'off');
else
    enable_video_encode(handles, 'on');
end


% --- Executes on selection change in video_compression_popup.
function video_compression_popup_Callback(hObject, eventdata, handles)
% hObject    handle to video_compression_popup (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: contents = cellstr(get(hObject,'String')) returns video_compression_popup contents as cell array
%        contents{get(hObject,'Value')} returns selected item from video_compression_popup
try
    strarr = cellstr(get(handles.video_compression_popup,'String'));
    sel = strarr{get(handles.video_compression_popup,'Value')};
    if(strcmp(sel, 'H.264'))
        bitrate_tog = 'on';
    else
        bitrate_tog = 'off';
    end
    set(handles.video_bitrate_label, 'Enable', bitrate_tog);
    set(handles.video_bitrate_text, 'Enable', bitrate_tog);
    set(handles.video_bitrate_units_label, 'Enable', bitrate_tog);
catch exception
    gui_exception(exception);
end


% --- Executes during object creation, after setting all properties.
function video_compression_popup_CreateFcn(hObject, eventdata, handles)
% hObject    handle to video_compression_popup (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: popupmenu controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end
